package com.lagou.rpc.zookeeper.metrics;

import com.lagou.rpc.zookeeper.config.ConfigKeeper;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 请求耗时统计，单位：ms
 */
public class RequestMetrics {
    //节点最后一次耗时
    private static final ConcurrentHashMap<String,Long> COST_TIME_MAP = new ConcurrentHashMap<>();
    //请求ID--耗时对象
    private static final ConcurrentHashMap<String,Metrics> REQUEST_ID_MAP = new ConcurrentHashMap<String, Metrics>();
    private static volatile RequestMetrics requestMetrics;

    private RequestMetrics(){}

    public ConcurrentHashMap<String,Long> getMetricMap(){
        return COST_TIME_MAP;
    }

    public static RequestMetrics getInstance(){
        if (null==requestMetrics){
            synchronized (ConfigKeeper.class){
                requestMetrics = new RequestMetrics();
            }
        }
        return requestMetrics;
    }

    /**增加节点*/
    public void addNode(String ip,int port){
        COST_TIME_MAP.put(ip+":"+port,0L);
    }

    /**移除节点*/
    public void removeNode(String ip,int port){
        COST_TIME_MAP.remove(ip+":"+port);
    }

    /**在客户端接到响应时，根据requestId计算耗时*/
    public void calculate(String requestId){
        Metrics metrics = REQUEST_ID_MAP.get(requestId);
        long cost = System.currentTimeMillis() - metrics.getStart();
        COST_TIME_MAP.put(metrics.getIp()+":"+metrics.getPort(),cost);
        REQUEST_ID_MAP.remove(requestId);
    }

    /**请求服务端时放入*/
    public void put(String ip,int port,String requestId){
        REQUEST_ID_MAP.put(requestId,new Metrics(ip,port,System.currentTimeMillis(),null));
    }

    /**
     * 获取所有节点耗时统计
     */
    public List<Metrics> getAllInstances(){
        List<Metrics> result = new ArrayList<>();
        COST_TIME_MAP.forEach((s,aLong)->{
            String[] split = s.split(":");
            result.add(new Metrics(split[0],Integer.parseInt(split[1]),aLong));
        });
        return result;
    }


    /**
     * 数据统计类
     */
    public static class Metrics implements Comparable<Metrics>{
        private String ip;
        private int port;
        private Long start;
        private Long cost;

        public Metrics(String ip, int port, Long cost) {
            this.ip = ip;
            this.port = port;
            this.cost = cost;
        }

        public Metrics(String ip, int port, Long start, Long cost) {
            this.ip = ip;
            this.port = port;
            this.start = start;
            this.cost = cost;
        }

        @Override
        public int compareTo(Metrics o) {
            return getCost().compareTo(o.getCost());
        }


        public String getIp() {
            return ip;
        }

        public void setIp(String ip) {
            this.ip = ip;
        }

        public int getPort() {
            return port;
        }

        public void setPort(int port) {
            this.port = port;
        }

        public Long getStart() {
            return start;
        }

        public void setStart(Long start) {
            this.start = start;
        }

        public Long getCost() {
            return cost;
        }

        public void setCost(Long cost) {
            this.cost = cost;
        }
    }




}
